﻿
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
namespace AppDesigner.Shared
{
    public class EventToCommand : TriggerAction<DependencyObject>
    {
        #region Fields
        private bool? _mustToogleValue;
        private object _commandParameterValue;
        #endregion

        #region DependencyProperty

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(EventToCommand), new PropertyMetadata(null,OnCommandChanged));

        private static void OnCommandChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            EventToCommand etc = (EventToCommand)sender;
            if (e.OldValue != null)
            {
                ((ICommand)e.OldValue).CanExecuteChanged -= etc.OnCommandCanExecuteChanged;
            }

            var command = (ICommand)e.NewValue;
            if (command != null)
            {
                command.CanExecuteChanged += etc.OnCommandCanExecuteChanged;
            }
            etc.EnableDisableElement();
        }

        private void OnCommandCanExecuteChanged(object sender, System.EventArgs e)
        {
            EnableDisableElement();
        }

        public object CommandParameter
        {
            get { return (object)GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CommandParameter.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(EventToCommand), new PropertyMetadata(null, OnCommandParameterChanged));

        private static void OnCommandParameterChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            EventToCommand etc = (EventToCommand)sender;
            if (etc == null || etc.AssociatedObject == null)
            {
                return;
            }
            etc.EnableDisableElement();
        }

        public bool MustToogleIsEnabled
        {
            get { return (bool)GetValue(MustToogleIsEnabledProperty); }
            set { SetValue(MustToogleIsEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MustToogleIsEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MustToogleIsEnabledProperty =
            DependencyProperty.Register("MustToogleIsEnabled", typeof(bool), typeof(EventToCommand), new PropertyMetadata(OnMustToogleIsEnabledChanged));

        private static void OnMustToogleIsEnabledChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            EventToCommand etc = (EventToCommand)sender;
            if (etc == null || etc.AssociatedObject == null)
            {
                return;
            }
            etc.EnableDisableElement();
        }
        #endregion

        #region Property
        public object CommandParameterValue
        {
            get { return _commandParameterValue; }
            set
            {
                _commandParameterValue = value;
                EnableDisableElement();
            }
        }

        public bool MustToogleIsEnabledValue
        {
            get
            {
                return _mustToogleValue == null ? MustToogleIsEnabled : _mustToogleValue.Value;
            }
            set
            {
                _mustToogleValue = value;
                EnableDisableElement();
            }
        }

        public bool PassEventArgsToCommand { get; set; }
        #endregion

        #region Override

        public void Invoke()
        {
            Invoke(null);
        }

        protected override void Invoke(object parameter)
        {
            if (AssociateElementIsDisabled())
            {
                return;
            }
            var command = GetCommand();
            var commandParameter = CommandParameterValue;

            if (commandParameter == null && PassEventArgsToCommand)
            {
                commandParameter = parameter;
            }

            if (command != null && command.CanExecute(commandParameter))
            {
                command.Execute(commandParameter);
            }
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            EnableDisableElement();
        }

        #endregion

        #region Method

        private void EnableDisableElement()
        {
            var element = GetAssociateObject();
            if (element == null)
            {
                return;
            }
            var command = GetCommand();

            if (MustToogleIsEnabledValue && command != null)
            {
                element.IsEnabled = command.CanExecute(CommandParameterValue);
            }
        }

        private ICommand GetCommand()
        {
            return Command;
        }

        private FrameworkElement GetAssociateObject()
        {
            return AssociatedObject as FrameworkElement;
        }

        private bool AssociateElementIsDisabled()
        {
            var element = GetAssociateObject();
            return AssociatedObject == null || (element != null && !element.IsEnabled);
        }

        #endregion
        

    }
}